home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / module.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-12  |  16.2 KB  |  661 lines  |  [TEXT/KAHL]

  1. /* Game modules for Xconq.
  2.    Copyright (C) 1991, 1992, 1993, 1994 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10.  
  11. extern int canaddutype, canaddmtype, canaddttype;
  12.  
  13. /* List of all known modules. Their descriptions can co-exist in memory,
  14.    even if their contents cannot. */
  15.  
  16. Module *modulelist = NULL;
  17.  
  18. /* The main module defining the game in effect. */
  19.  
  20. Module *mainmodule = NULL;
  21.  
  22. char *moduledesigbuf = NULL;
  23.  
  24. /* Empty out the list of modules. */
  25.  
  26. void
  27. clear_game_modules()
  28. {
  29.     modulelist = mainmodule = NULL;
  30. }
  31.  
  32. /* Create a brand-new game module. */
  33.  
  34. Module *
  35. create_game_module(name)
  36. char *name;
  37. {
  38.     Module *module = (Module *) xmalloc(sizeof(Module));
  39.  
  40.     /* Nullify/zeroify most module slots. */
  41.     memset(module, 0, sizeof(Module));
  42.     /* Fill in nonzero slots. */
  43.     /* The module's name must never be NULL. */
  44.     if (name == NULL) name = "";
  45.     module->name = name;
  46.     module->instructions = lispnil;
  47.     module->notes = lispnil;
  48.     module->designnotes = lispnil;
  49.     module->startlineno = 1;
  50.     module->endlineno = 1;
  51.     /* Add to front of module list. */
  52.     module->next = modulelist;
  53.     modulelist = module;
  54.     return module;
  55. }
  56.  
  57. Module *
  58. find_game_module(name)
  59. char *name;
  60. {
  61.     Module *module;
  62.  
  63.     if (name != NULL) {
  64.     for_all_modules(module) {
  65.         if (module->name && strcmp(name, module->name) == 0) return module;
  66.     }
  67.     }
  68.     return NULL;
  69. }
  70.  
  71.  
  72. /* Produce a module of the given name, either by finding it or creating it. */
  73.  
  74. Module *
  75. get_game_module(name)
  76. char *name;
  77. {
  78.     Module *module = find_game_module(name);
  79.  
  80.     if (module != NULL) return module;
  81.     return create_game_module(name);
  82. }
  83.  
  84. /* Make a game module for the given name and maybe bolt it into the include
  85.    list of another module. */
  86.  
  87. Module *
  88. add_game_module(name, includer)
  89. char *name;
  90. Module *includer;
  91. {
  92.     Module *module = get_game_module(name), *other;
  93.  
  94.     if (includer) {
  95.     /* Add to the end of the list of include files. */
  96.     if (includer->include == NULL) {
  97.         includer->include = includer->lastinclude = module;
  98.     } else {
  99.         for (other = includer->include; other != NULL; other = other->nextinclude) {
  100.         /* already here, just return it. */
  101.         if (module == other) return module;
  102.         }
  103.         includer->lastinclude->nextinclude = module;
  104.         includer->lastinclude = module;
  105.     }
  106.     } else {
  107.     /* an error? */
  108.     }
  109.     return module;
  110. }
  111.  
  112. /* Display game module info to a side. */
  113.  
  114. void
  115. describe_game_modules(arg, key, buf)
  116. int arg;
  117. char *key, *buf;
  118. {
  119.     if (mainmodule != NULL) {
  120.     /* First put out basic module info. */
  121.     describe_game_module_aux(buf, mainmodule, 0);
  122.     /* Now do the lengthy module notes (with no indentation). */
  123.     describe_module_notes(buf, mainmodule);
  124.     } else {
  125.     sprintf(buf, "(No game module information is available.)");
  126.     }
  127. }
  128.  
  129. /* Recurse down through included modules to display docs on each.
  130.    Indents each file by inclusion level.  Note that modules cannot
  131.    be loaded more than once, so each will be described only once here. */
  132.  
  133. void   
  134. describe_game_module_aux(buf, module, level)
  135. char *buf;
  136. Module *module;
  137. int level;
  138. {
  139.     int i;
  140.     char indentbuf[100];
  141.     Module *submodule;
  142.  
  143.     indentbuf[0] = '\0';
  144.     for (i = 0; i < level; ++i) {
  145.     strcat(indentbuf, "  ");
  146.     }
  147.     tprintf(buf, "%s\"%s\"", indentbuf,
  148.         (module->title ? module->title : module->name));
  149.     if (module->title == NULL) {
  150.     tprintf(buf, " (\"%s\")", module->name);
  151.     }
  152.     if (module->version != NULL) {
  153.     tprintf(buf, " (version \"%s\")", module->version);
  154.     }
  155.     tprintf(buf, "\n");
  156.     tprintf(buf, "%s          %s\n",
  157.         indentbuf,
  158.         (module->blurb ? module->blurb : "(no description)"));
  159.     if (module->notes != lispnil) {
  160.     tprintf(buf, "%s          (See notes below)\n", indentbuf);
  161.     }
  162.     /* Now describe any included modules. */
  163.     for_all_includes(module, submodule) {
  164.     describe_game_module_aux(buf, submodule, level + 1);
  165.     }
  166. }
  167.  
  168. /* Dump the module player's and designer's notes into the given buffer. */
  169.  
  170. void
  171. describe_module_notes(buf, module)
  172. char *buf;
  173. Module *module;
  174. {
  175.     Module *submodule;
  176.  
  177.     if (module->notes != lispnil) {
  178.     tprintf(buf, "\nNotes to \"%s\":\n", module->name);
  179.     append_notes(buf, module->notes);
  180.     }
  181.     /* Only show design notes if any designers around. */
  182.     if (numdesigners > 0 && module->designnotes != lispnil) {
  183.     tprintf(buf, "\nDesign Notes to \"%s\":\n", module->name);
  184.     append_notes(buf, module->designnotes);
  185.     }
  186.     for_all_includes(module, submodule) {
  187.     describe_module_notes(buf, submodule);
  188.     }
  189. }
  190.  
  191. /* Sometimes we find ourselves lacking a game to provide meaning and
  192.    context for interpretation; this routine loads the standard game
  193.    (or a specified alternative default) immediately, but only makes
  194.    it the main module if none defined. */
  195.  
  196. void
  197. load_default_game()
  198. {
  199.     extern char *standard_game_name;
  200.     char *defaultname = standard_game_name;
  201.     Module *module;
  202.  
  203.     /* If we have a different default module, use it instead. */
  204.     if (mainmodule != NULL && mainmodule->defaultbasemodulename != NULL) {
  205.         defaultname = mainmodule->defaultbasemodulename;
  206.     }
  207.     module = get_game_module(defaultname);
  208.     if (mainmodule == NULL) mainmodule = module;
  209.     load_game_module(module, TRUE);
  210. }
  211.  
  212. /* Attempt to read just the first form in a module and use it as a
  213.    description of the module.  Return true if this worked, false
  214.    otherwise. */
  215.  
  216. int
  217. load_game_description(module)
  218. Module *module;
  219. {
  220.     Obj *form, *thecar;
  221.     char *name;
  222.  
  223.     if (open_module(module, FALSE)) {
  224.     if ((form = read_form(module->fp,
  225.                   &(module->startlineno),
  226.                   &(module->endlineno)))
  227.         != lispeof) {
  228.         if (consp(form) && symbolp(thecar = car(form))) {
  229.         name = c_string(thecar);
  230.         if (keyword_code(name) == K_GAME_MODULE) {
  231.             interp_game_module(form, module);
  232.             close_module(module);
  233.             /* Note that module is still not considered "loaded". */
  234.             return TRUE;
  235.         }
  236.         }
  237.     }
  238.     }
  239.     return FALSE;
  240. }
  241.  
  242. /* Game files can live in library directories or somewhere else.  This
  243.    function tries to find a file, open it, and load the contents. */
  244.  
  245. void
  246. load_game_module(module, dowarn)
  247. Module *module;
  248. int dowarn;
  249. {
  250.     char ch;
  251.  
  252.     if (open_module(module, dowarn)) {
  253.     if (module->fp) {
  254.         /* Peek at the first character - was 'X' in old format files. */
  255.         ch = getc(module->fp);
  256.         ungetc(ch, module->fp);
  257.         if (ch == 'X') {
  258.         init_error("\"%s\" is probably an obsolete Xconq file; in any case, it cannot be used.",
  259.                module->filename);
  260.         } else {
  261.         /* New format, read it all. */
  262.         read_forms(module);
  263.         }
  264.     } else {
  265.         /* (should be able to read from contents string) */
  266.     }
  267.     /* We're done, can close. */
  268.     close_module(module);
  269.     /* Mark the module as having been loaded - note that this will happen
  270.        even if there were horrible errors. */
  271.     module->loaded = TRUE;
  272.     /* If the turn number has been set explicitly to a positive value,
  273.        assume that a saved game is being restored into the middle of the turn. */
  274.     if (g_turn() > 0)
  275.       midturnrestore = TRUE;
  276.     /* If the random state has been set explicitly to a nonnegative value,
  277.        use it to reseed the generator. */
  278.     if (g_random_state() >= 0)
  279.       init_xrandom(g_random_state());
  280.     /* Make all the cross-references right. */
  281.     patch_object_references();
  282.     /* Are all the types staked down now? */
  283.     if (!canaddutype && !canaddmtype && !canaddttype) {
  284.         typesdefined = TRUE;
  285.         /* (should also record this as a sort of base module?) */
  286.     }
  287.     }
  288. }
  289.  
  290. void
  291. load_base_module(module)
  292. Module *module;
  293. {
  294.     char *basename = module->basemodulename;
  295.     Module *basemodule;
  296.  
  297.     if (!empty_string(basename)) {
  298.     basemodule = find_game_module(basename);
  299.     if (basemodule == NULL)
  300.       basemodule = add_game_module(basename, module);
  301.     if (basemodule->loaded) {    
  302.         Dprintf("Base module `%s' already loaded.\n", basename);
  303.     } else {
  304.         Dprintf("Loading base module `%s' ...\n", basename);
  305.         load_game_module(basemodule, FALSE);
  306.         Dprintf("... Done loading `%s'.\n", basename);
  307.     }
  308.     }
  309. }
  310.  
  311. /* Given a module, attempt to open it. */
  312.  
  313. int
  314. open_module(module, dowarn)
  315. Module *module;
  316. int dowarn;
  317. {
  318.     FILE *fp = NULL;
  319.  
  320.     /* Don't open more than once. */
  321.     if (module->open && dowarn) {
  322.     init_warning("Module \"%s\" is already open, ignoring attempt to reopen",
  323.              module->name);
  324.     return FALSE;
  325.     }
  326.     /* Don't open if already loaded. */
  327.     if (module->loaded && dowarn) {
  328.     init_warning("Module \"%s\" is already loaded, ignoring attempt to reload",
  329.              module->name);
  330.     return FALSE;
  331.     }
  332.     if (module->contents) {
  333.     /* Uninterpreted contents already available, init the ptr. */
  334.     module->sp = module->contents;
  335.     Dprintf("Reading module \"%s\" from string ...\n", module->name);
  336.     } else if ((fp = open_module_library_file(module)) != NULL) {
  337.     /* Found the module in a library directory. */
  338.     Dprintf("Reading module \"%s\" from library file \"%s\" ...\n",
  339.         module->name, module->filename);
  340.     module->fp = fp;
  341.     } else if ((fp = open_module_explicit_file(module)) != NULL) {
  342.     Dprintf("Reading module \"%s\" from file \"%s\" ...\n",
  343.         module->name, module->filename);
  344.     module->fp = fp;
  345.     } else {
  346.     if (dowarn) {
  347.         if (module->name) {
  348.             init_warning("Can't find module \"%s\" anywhere",
  349.                  module->name);
  350.         } else {
  351.             init_warning("Can't find unnamed module anywhere");
  352.         }
  353.     }
  354.     return FALSE;
  355.     }
  356.     /* It worked, mark this module as open. */
  357.     module->open = TRUE;
  358.     return TRUE;
  359. }
  360.  
  361. /* Read info about a side's preferences and setup. */
  362.  
  363. /* This assumes one form only, probably too restrictive. */
  364. /* should read all the forms, use the relevant ones. */
  365. /* (how does this interact with other defaults?) */
  366. /* (should be delayed until player can confirm it...) */
  367.  
  368. /* (update to work like other module stuff? then can use resources etc) */
  369. /* (fix so that correct name can be found reliably) */
  370.  
  371. int
  372. load_side_config(side)
  373. Side *side;
  374. {
  375. #if 0
  376.     FILE *fp;
  377.     Obj *config;
  378.     Module *module;
  379.  
  380.     /* (should incorp config name somehow, also be sys-dependent) */
  381.     module = create_game_module(side->player->name);
  382.  
  383.     if ((module->fp = fopen(module->filename, "r")) != NULL) {
  384.     if ((config = read_form(module->fp,
  385.                 &(module->startlineno),
  386.                 &(module->endlineno)))
  387.         != lispeof) {
  388.         /* interpret the config */
  389.         Dprintf("Interpreting %s config form", side_desig(side));
  390.         Dprintlisp(config);
  391.         Dprintf("\n");
  392.         fill_in_side(side, config, TRUE);
  393.     } else {
  394.         /* no config form in the file */
  395.     }
  396.     } else {
  397.     init_warning("Module \"%s\" could not be opened", module->name);
  398.     /* Not a disaster, keep going */
  399.     }
  400. #endif
  401.     return FALSE;
  402. }
  403.  
  404. /* Read an entire file, attempting to pick up objects in it. */
  405.  
  406. /* (does this interp game-module form twice if description previously
  407.    loaded?) */
  408.  
  409. void
  410. read_forms(module)
  411. Module *module;
  412. {
  413.     Obj *form;
  414.  
  415.     Dprintf("Trying to read a new format file \"%s\"...\n", module->name);
  416.     while ((form = read_form(module->fp,
  417.                  &(module->startlineno),
  418.                  &(module->endlineno)))
  419.        != lispeof) {
  420.     interp_form(module, form);
  421.     }
  422.     Dprintf("... Done reading \"%s\".\n", module->name);
  423. }
  424.  
  425. void
  426. init_module_reshape(module)
  427. Module *module;
  428. {
  429.     /* Seed all the reshaping parameters with reasonable values. */
  430.     module->maybereshape = TRUE;
  431.     module->subareawidth = area.width;
  432.     module->subareaheight = area.height;
  433.     module->subareax = module->subareay = 0;
  434.     module->finalsubareawidth = area.width;
  435.     module->finalsubareaheight = area.height;
  436.     module->finalsubareax = module->finalsubareay = 0;
  437.     module->finalwidth = area.width;  module->finalheight = area.height;
  438.     module->finalcircumference = world.circumference;
  439.     module->filltype = 0;
  440. }
  441.  
  442. /* This is true if any actual reshaping is required. */
  443.  
  444. int
  445. reshape_the_output(module)
  446. Module *module;
  447. {
  448.     return (module->maybereshape
  449.         && (module->subareawidth != area.width
  450.         || module->subareaheight != area.height
  451.         || module->subareax != 0
  452.         || module->subareay != 0
  453.         || module->finalsubareawidth != area.width
  454.         || module->finalsubareaheight != area.height
  455.         || module->finalsubareax != 0
  456.         || module->finalsubareay != 0
  457.         || module->finalwidth != area.width
  458.         || module->finalheight != area.height
  459.         || module->finalcircumference != world.circumference));
  460. }
  461.  
  462. /* Check if the proposed reshape will actually work. */
  463.  
  464. int
  465. valid_reshape(module)
  466. Module *module;
  467. {
  468.     /* (should check hexagon shaping) */
  469.     if (module->subareawidth > area.width
  470.     || module->subareaheight > area.height) return FALSE;
  471.     /* (should check other offsets) */
  472.     if (module->finalwidth < 3 || module->finalheight < 3) return FALSE;
  473.     return TRUE;
  474. }
  475.  
  476. /* Close the module. */
  477.  
  478. void
  479. close_module(module)
  480. Module *module;
  481. {
  482.     if (module->sp) {
  483.     module->sp = NULL;
  484.     }
  485.     if (module->fp) {
  486.     fclose(module->fp);
  487.     module->fp = NULL;
  488.     }
  489.     module->open = FALSE;
  490. }
  491.  
  492. /* Return a description of the module. */
  493.  
  494. char *
  495. module_desig(module)
  496. Module *module;
  497. {
  498.     if (moduledesigbuf == NULL) moduledesigbuf = xmalloc(BUFSIZE);
  499.     sprintf(moduledesigbuf, "module %s (%s)",
  500.         module->name, (module->title ? module->title : "no title"));
  501.     return moduledesigbuf;
  502. }
  503.  
  504. /* (random check, should be sent to right places) */
  505.  
  506. #ifdef DEBUGGING
  507. /* Use this to ensure that everything is cool. */
  508.  
  509. void
  510. doublecheck_state(side)
  511. Side *side;
  512. {
  513.     Unit *unit;
  514.  
  515.     for_all_units(unit) {
  516.     if (unit->x < 0 || unit->x >= area.width ||
  517.         unit->y <= 0 || unit->y >= (area.height - 1) ||
  518.         unit->hp <= 0) {
  519.         Dprintf("%s off map hp %d", unit_desig(unit), unit->hp);
  520.     }
  521.     }
  522. }
  523. #endif /* DEBUGGING */
  524.  
  525. #if 0 /* unused */
  526. /* Return the value of an extension, or the default if it wasn't found. */
  527.  
  528. long
  529. extension_value(extensions, key, dflt)
  530. Obj *extensions;
  531. char *key;
  532. long dflt;
  533. {
  534.     Obj *bdg, *val;
  535.  
  536.     for ( ; extensions != lispnil; extensions = cdr(extensions)) {
  537.     bdg = car(extensions);
  538.     if (consp(bdg)
  539.         && symbolp(car(bdg))
  540.         && strcmp(c_string(car(bdg)), key) == 0) {
  541.         val = cadr(bdg);
  542.         /* Return number or string directly, Lisp value otherwise. */
  543.         if (numberp(val)) {
  544.         return c_number(val);
  545.         } else if (stringp(val)) {
  546.         return ((long) c_string(val));
  547.         } else {
  548.         return ((long) val);
  549.         }
  550.     }
  551.     }
  552.     return dflt;
  553. }
  554. #endif
  555.  
  556. void set_u_internal_name(u, s) int u; char *s; { utypes[u].iname = s; }
  557. void set_u_type_name(u, s) int u; char *s; { utypes[u].name = s; }
  558. void set_m_type_name(m, s) int m; char *s; { mtypes[m].name = s; }
  559. void set_t_type_name(t, s) int t; char *s; { ttypes[t].name = s; }
  560.  
  561. /* If a special symbol, we might not have to fail. */
  562.  
  563. int
  564. lazy_bind(sym)
  565. Obj *sym;
  566. {
  567.     int u, m, t;
  568.     Obj *value;
  569.  
  570.     switch (keyword_code(c_string(sym))) {
  571.       case K_USTAR:
  572.     value = lispnil;
  573.     /* Since consing glues onto the front, iterate backwards
  574.        through the types. */
  575.     for (u = numutypes - 1; u >= 0; --u) {
  576.         value = cons(new_utype(u), value);
  577.     }
  578.     break;
  579.       case K_MSTAR:
  580.     value = lispnil;
  581.     for (m = nummtypes - 1; m >= 0; --m) {
  582.         value = cons(new_mtype(m), value);
  583.     }
  584.     break;
  585.       case K_TSTAR:
  586.     value = lispnil;
  587.     for (t = numttypes - 1; t >= 0; --t) {
  588.         value = cons(new_ttype(t), value);
  589.     }
  590.     break;
  591.       default:
  592.     return FALSE;
  593.     }
  594.     setq(sym, value);
  595.     return TRUE;
  596. }
  597.  
  598. /* (should be in lisp.c, need to change _code to _value lookup on symbols) */
  599.  
  600. int
  601. eval_boolean_expression(expr, fn, dflt)
  602. Obj *expr;
  603. int (*fn) PROTO ((Obj *)), dflt;
  604. {
  605.     char *opname;
  606.  
  607.     if (expr == lispnil) {
  608.     return dflt;
  609.     } else if (consp(expr) && symbolp(car(expr))) {
  610.     opname = c_string(car(expr));
  611.     switch (keyword_code(opname)) {
  612.         case K_AND:
  613.         return (eval_boolean_expression(cadr(expr), fn, dflt)
  614.             && eval_boolean_expression(car(cddr(expr)), fn, dflt));
  615.         case K_OR:
  616.         return (eval_boolean_expression(cadr(expr), fn, dflt)
  617.             || eval_boolean_expression(car(cddr(expr)), fn, dflt));
  618.         case K_NOT:
  619.         return !eval_boolean_expression(cadr(expr), fn, dflt);
  620.         default:
  621.         return (*fn)(expr);
  622.     }
  623.     } else {
  624.     return (*fn)(expr);
  625.     }
  626. }
  627.  
  628. int
  629. coerce_to_side_id(x)
  630. Obj *x;
  631. {
  632.     if (numberp(x)) {
  633.     return c_number(x);
  634.     }
  635.     return 0;
  636. }
  637.  
  638. Side *
  639. coerce_to_side(x)
  640. Obj *x;
  641. {
  642.     return side_n(coerce_to_side_id(x));
  643. }
  644.  
  645. int
  646. coerce_to_unit_id(x)
  647. Obj *x;
  648. {
  649.     if (numberp(x)) {
  650.     return c_number(x);
  651.     }
  652.     return 0;
  653. }
  654.  
  655. Unit *
  656. coerce_to_unit(x)
  657. Obj *x;
  658. {
  659.     return find_unit(coerce_to_unit_id(x));
  660. }
  661.